#include "../include/KeyRecommander.hpp"
#include "../include/net/TcpConnection.hpp"

#include <iostream>

using namespace std;
namespace wd{

void KeyRecommander::queryforEn(const char &ch){  //英文查找
        string index;
        index += ch;
        set<int> temp = _dictionary->getIndexTable()[index];
        for(auto &elem: temp){
            _set.insert(elem);
        }
}


int KeyRecommander::queryforNum(const char* p){
        int offset = 0;   
        const char* temp = p;
        string index;
        while(*temp >= '0' && *temp <= '9'){
           index += *temp;
           ++temp;
           ++offset;
        }
    //    cout << "index:" << index <<endl;
    
        set<int> temp1 = _dictionary->getIndexTable()[index];
        for(auto &elem : temp1){
            _set.insert(elem);
        }
        return offset;
}

int count(const char &ch){
   int ans = 0; 
   int index = 7;
   int num = 1;
   while((num << index )& ch){
        ++ans;
        --index;
   }
   return ans;
}



void  KeyRecommander::queryforCn(const char *p, int offset){  //中文查找
         string index;
         for(int j = 0 ; j <  offset; ++j){
            index += p[j];
         }
         std::cout << "index = " << index << endl;
         set<int> temp = _dictionary->getIndexTable()[index];
         /* std::cout << "索引表:" << endl; */ 
         for(auto &elem: temp){
            _set.insert(elem - 1);//-1
            /* printf("elem:%d " ,elem); */
         }

}

void KeyRecommander::doQuery(const TcpConnectionPtr& ptr){
    excute();

    string temp("");
    print(temp);

    ptr->sendInEventLoop(temp);
    std::cout << "sendInEventLoop(print())" << endl;
}

void KeyRecommander::excute(){
    queryIndexTable();
    std::cout << "In excute:after queryIndexTable" << endl;
    statistic(_set);
    std::cout << "In excute:after statistic(_set)" << endl;
}



void KeyRecommander::queryIndexTable(){
    char *p = &_queryWord[0];
    int offset = 0;
    while(*p != '\0'){
    if( *p >= 'a' && *p <= 'z'){
        puts("1");
        queryforEn(*p); 
        ++p;
    }else if(*p >= '0' && *p <= '9'){
        puts("2");
        int ret = queryforNum(p);
        printf("ret:%d\n", ret);
        p += ret;
    }
    else{
        puts("3");
        offset = count(*p);
        printf("offset:%d\n", offset);
        queryforCn(p, offset);
        p += offset;
    }
    }
        
}

void KeyRecommander::statistic(set<int>& set){
    std::vector<std::pair<string, int>>  _dic = _dictionary->getDict();
    for(auto &elem: set){
        int index = elem; 
        string candicate = _dic[index].first;
        /* std::cout<< "set:" << elem << " candicate:" << candicate <<endl; */
        int freq = _dic[index].second;
        int dis = distance(candicate);
        _resultque.push(MyResult(candicate, freq, dis));
    } 
    
}

size_t nBytesCode(const char ch)
{
	if(ch & (1 << 7))
	{
		int nBytes = 1;
		for(int idx = 0; idx != 6; ++idx)
		{
			if(ch & (1 << (6 - idx)))
			{
				++nBytes;	
			}
			else
				break;
		}
		return nBytes;
	}
	return 1;
}  
  
std::size_t length(const std::string &str)
{
	std::size_t ilen = 0;
	for(std::size_t idx = 0; idx != str.size(); ++idx)
	{
		int nBytes = nBytesCode(str[idx]);
		idx += (nBytes - 1);
		++ilen;
	}
	return ilen;
}

int triple_min(const int &a, const int &b, const int &c)
{
	return a < b ? (a < c ? a : c) : (b < c ? b : c);
}

int editDistance(const std::string & lhs, const std::string &rhs)
{//计算最小编辑距离-包括处理中英文
	size_t lhs_len = length(lhs);
	size_t rhs_len = length(rhs);
	int editDist[lhs_len + 1][rhs_len + 1];
	for(size_t idx = 0; idx <= lhs_len; ++idx)
	{
		editDist[idx][0] = idx;
	}

	for(size_t idx = 0; idx <= rhs_len; ++idx)
	{
		editDist[0][idx] = idx;
	}
	
	std::string sublhs, subrhs;
	for(std::size_t dist_i = 1, lhs_idx = 0; dist_i <= lhs_len; ++dist_i, ++lhs_idx)
	{
		size_t nBytes = nBytesCode(lhs[lhs_idx]);
		sublhs = lhs.substr(lhs_idx, nBytes);
		lhs_idx += (nBytes - 1);

		for(std::size_t dist_j = 1, rhs_idx = 0; dist_j <= rhs_len; ++dist_j, ++rhs_idx)
		{
			nBytes = nBytesCode(rhs[rhs_idx]);
			subrhs = rhs.substr(rhs_idx, nBytes);
			rhs_idx += (nBytes - 1);
			if(sublhs == subrhs)
			{
				editDist[dist_i][dist_j] = editDist[dist_i - 1][dist_j - 1];
			}
			else
			{
				editDist[dist_i][dist_j] = triple_min(
					editDist[dist_i][dist_j - 1] + 1,
					editDist[dist_i - 1][dist_j] + 1,
					editDist[dist_i - 1][dist_j - 1] + 1);
			}
		}
	}
	return editDist[lhs_len][rhs_len];
}

int KeyRecommander::distance(const string &rhs){
    return editDistance(_queryWord, rhs);   
}




}
